#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* 文件系统名称, 同时作为文件名在退出系统时保存所有信息 */
#define extFS 		  "extFS"
#define BACKUP_FILE   "extFS_backup"

/* 块大小, 索引节点大小 */
#define BLOCK_SIZE 1024
#define INODE_SIZE 128

/* 块数量, 索引节点数量 */
#define BLOCK_NUM 1048576
#define INODE_NUM 8192

/* 块组信息 */
#define BLOCKNUM_PER_GROUP   (BLOCK_SIZE/4)
#define BLOCKGROUP_NUM       (BLOCK_NUM/BLOCKNUM_PER_GROUP)
#define BLOCKGROUP_SIZE      (BLOCKNUM_PER_GROUP*BLOCK_SIZE)

/* 文件项信息 */
#define CATALOG_SIZE         32
#define FILENAME_MAX2        (CATALOG_SIZE-4)
#define CATALOGNUM_PER_BLOCK (BLOCK_SIZE/CATALOG_SIZE)

/* 文件类型和许可权限 */
#define CATALOG              01000
#define CATALOG_PERMISS      0755
#define NORMAL_FILE	         00000
#define NORMAL_FILE_PERMISS  0664

/* 日志打印宏定义 */
#define disk_read(pos,dest,size)  (fseek(g_ifp,pos,SEEK_SET),fread(dest,size,1,g_ifp),fflush(g_ifp))
#define disk_write(pos,from,size) (fseek(g_ofp,pos,SEEK_SET),fwrite(from,size,1,g_ofp),fflush(g_ofp))
#define print(x)  (printf("%d: %s\n",__LINE__,x))
#define printd(x) (printf("%d: %d\n",__LINE__,x))
#define cmdis(x)  (!strcmp(cmd,x))
#define GB (1024*1024*1024)
#define MB (1024*1024)
#define KB (1024)

/* 超级块定义 */
typedef struct {
	u_int32_t superblock_size;
	u_int32_t block_size;
	u_int32_t inode_size;
	u_int32_t block_num;
	u_int32_t inode_num;
	u_int32_t free_block_num;
	u_int32_t free_inode_num;
	u_int32_t blocknum_per_group;
	u_int32_t superblock_addr;
	u_int32_t inode_bitmap_addr;
	u_int32_t block_bitmap_addr;
	u_int32_t inode_addr;
	u_int32_t block_addr;
	u_int32_t disk_size;
	u_int32_t free_addr;
	u_int32_t free[BLOCKNUM_PER_GROUP];
} superblock;

/* 索引节点定义 */
typedef struct {
	char user[20];
	char group[20];
	u_int16_t id;						/*  */
	u_int16_t access;
	u_int16_t count;
	u_int32_t filesize;
	u_int32_t direct_block[10];
	u_int32_t indirect_block1;			/* 1024/4 * 1K = 256K */
	u_int32_t indirect_block2;			/* 256 * 256K = 64M */
	u_int32_t indirect_block3;			/* 256 * 64M = 16G */
	time_t  ctime;						/* inode上一次变动的时间 */
	time_t  mtime;						/* 文件内容上一次变动的时间 */
	time_t  atime;						/* 文件上一次打开的时间 */
} inode;

/* 文件项定义 */
typedef struct {
	char filename[FILENAME_MAX2];
	u_int32_t inode_addr;
} catalog;

/* 结构地址信息 */
const u_int32_t gc_superblock_addr = 0;	/* 超级块放在磁盘最前面 */
const u_int32_t gc_block_bitmap_addr = (sizeof(superblock)/BLOCK_SIZE + 1) * BLOCK_SIZE;
const u_int32_t gc_inode_bitmap_addr = gc_block_bitmap_addr + BLOCK_NUM;
const u_int32_t gc_inode_addr = gc_inode_bitmap_addr + INODE_NUM;
const u_int32_t gc_block_addr = gc_inode_addr + INODE_NUM * INODE_SIZE;
const u_int32_t gc_disk_size = gc_block_addr + BLOCK_NUM * BLOCK_SIZE;

/* 超级块 */
superblock g_superblock;

/* 虚拟磁盘文件读写指针 */
FILE *g_ifp;
FILE *g_ofp;

/* 当前用户和用户组 */
char g_curuser[100];
char g_curgroup[100];

/* 当前目录,当前用户主目录 */
char g_curdir[100];
char g_curuser_home[310];

/* 当前目录地址,根目录地址 */
int g_curdir_addr;
int g_rootdir_addr;

/* 数据块位图, 索引节点位图 */
char g_block_bitmap[BLOCK_NUM];
char g_inode_bitmap[INODE_NUM];

/* 系统函数 */
void fs_start();													/* 启动文件系统 */
void fs_ready();													/* 启动前准备 */
void fs_format();													/* 格式化磁盘 */
void fs_load();														/* 加载文件系统 */
void fs_diskinfo();													/* 打印磁盘信息 */
void fs_shell();													/* 交互控制程序 */
void block_alloc(u_int32_t *blockaddr);								/* 磁盘块分配 */
void block_free();													/* 磁盘块回收 */
void inode_alloc(u_int32_t *inodeaddr);								/* 索引节点分配 */
void inode_free();													/* 索引节点回收 */
void fs_mkdir(int curdir_addr, char *filename);
void fs_rmdir(int curdir_addr, char *filename);
void fs_rm(int curdir_addr, char *filename);
void fs_rm_rf(int inode_addr);
void fs_create(int curdir_addr, char *filename, char *buf);
void fs_ls(int curdir_addr);	
void fs_cd(int curdir_addr, char *filename);
void fs_chmod(int curdir_addr, char *access, char *filename);			
void fs_touch(int curdir_addr, char *filename);
void fs_write(int curdir_addr, char *filename);
void fs_cat(int curdir_addr, char *filename);
void fs_exit();
void rightbit(inode curdir_inode, int *bit);
void find_file_in_curdir(inode curdir_inode, char *filename, int *block_index, int *catalog_index, int *ret);
void bigfile();

/* 启动extFS */
void fs_start()
{
    if (g_ifp = fopen(BACKUP_FILE, "rb"))	/* 检查是否存在备份文件 */
    {
		g_ofp = fopen(extFS, "wb");
		
		char *buffer = (char*)malloc(sizeof(char)*BLOCKGROUP_SIZE);

		int disk_size = gc_disk_size;

		print("正在读磁盘。。。");
		int i = 1;
		while (disk_size > 0)
		{
			if (i++ == 3)
			{
				printf("%.2lf%%", (1 - (double)disk_size/gc_disk_size) * 100);
				printf("\r\033[k");
				i = 1;
			}

			if (disk_size > BLOCKGROUP_SIZE)
			{
				fread(buffer, BLOCKGROUP_SIZE, 1, g_ifp);
				fwrite(buffer, BLOCKGROUP_SIZE, 1, g_ofp);
			}
			else
			{
				fread(buffer, disk_size, 1, g_ifp);
				fwrite(buffer, disk_size, 1, g_ofp);
			}

			disk_size -= BLOCKGROUP_SIZE;
		}

		free(buffer);

		g_ifp = fopen(extFS, "rb");

		fs_ready();    /* 启动前准备 */

        fs_load();  /* 加载文件系统 */
    }
    else
    {
        g_ofp = fopen(extFS, "wb");    /* 先创建文件,再打开读指针 */
        g_ifp = fopen(extFS, "rb");

        fs_format();    /* 磁盘格式化 */
    }
}

/* 启动前准备 */
void fs_ready()
{
	sprintf(g_curuser, "root");
	sprintf(g_curgroup, "root");

	/* 将第一个inode地址赋值给根目录地址 */
	g_rootdir_addr = gc_inode_addr;
	g_curdir_addr = gc_inode_addr;

	/* 设置当前目录和当前用户主目录 */
	sprintf(g_curdir, "/");
	sprintf(g_curuser_home, "/root");	
}

/* 格式化磁盘,最大可用空间2GB */
void fs_format()
{
	fs_ready();

	/* 超级块大小 */
	g_superblock.superblock_size = sizeof(superblock);

	/* 块大小和索引节点大小 */
	g_superblock.block_size = BLOCK_SIZE;
	g_superblock.inode_size = sizeof(inode);

	/* 块数和索引节点数 */
	g_superblock.block_num = BLOCK_NUM;
	g_superblock.inode_num = INODE_NUM;

	/* 空闲块数和空闲节点数 */
	g_superblock.free_block_num = BLOCK_NUM;
	g_superblock.free_inode_num = INODE_NUM;

	/* 每个块组包含100个块 */
	g_superblock.blocknum_per_group = BLOCKNUM_PER_GROUP;

	/* 结构地址信息 */
	g_superblock.superblock_addr = gc_superblock_addr;
	g_superblock.block_bitmap_addr = gc_block_bitmap_addr;
	g_superblock.inode_bitmap_addr = gc_inode_bitmap_addr;
	g_superblock.inode_addr = gc_inode_addr;
	g_superblock.block_addr = gc_block_addr;

	/* 磁盘大小 */
	g_superblock.disk_size = gc_block_addr + BLOCK_NUM * BLOCK_SIZE;

	/* 空闲堆栈地址 */
	g_superblock.free_addr = gc_block_addr;	

    /* 初始化磁盘块区，根据成组链接法组织	 */
	for(int i=BLOCKGROUP_NUM-1; i>=0; i--)
    {
		if(i == BLOCKGROUP_NUM-1)
        {
            g_superblock.free[0] = -1;	/* -1表示没有空闲盘块 */
        }
		else
        {
            g_superblock.free[0] = gc_block_addr + (i+1) * BLOCKGROUP_SIZE;	/* 指向下一个空闲块 */
        }

        /* 初始化空闲盘块号栈 */
		for(int j=1; j<BLOCKNUM_PER_GROUP; j++)
        {
			g_superblock.free[j] = gc_block_addr + (i*BLOCKNUM_PER_GROUP + j) * BLOCK_SIZE;
		}

		/* 将空闲盘块号栈写入磁盘,在块组起始地址,占满第一个磁盘块 */
		disk_write(gc_block_addr + i * BLOCKGROUP_SIZE, g_superblock.free, sizeof(g_superblock.free));
	}

	/* 超级块写入到虚拟磁盘文件 */
	disk_write(gc_superblock_addr, &g_superblock, sizeof(superblock));

	/* 初始化inode位图 */
    memset(g_inode_bitmap, 0, sizeof(g_inode_bitmap));
    disk_write(gc_inode_bitmap_addr, g_inode_bitmap, sizeof(g_inode_bitmap));

    /* 初始化block位图 */
	memset(g_block_bitmap, 0, sizeof(g_block_bitmap));
	disk_write(gc_block_bitmap_addr, g_block_bitmap, sizeof(g_block_bitmap));

	/* 创建根目录 */
	inode rootdir;

	/* 申请inode,block */
	u_int32_t inode_addr, block_addr;
	inode_alloc(&inode_addr);
	block_alloc(&block_addr);

	/* 添加当前目录 */
	catalog catalogs[CATALOGNUM_PER_BLOCK] = {0};
	sprintf(catalogs[0].filename, ".");
	catalogs[0].inode_addr = inode_addr;

	/* 写回磁盘块 */
	disk_write(block_addr, catalogs, sizeof(catalogs));

	/* 对inode赋值 */
	rootdir.id = 0;
	rootdir.atime = time(NULL);
	rootdir.ctime = time(NULL);
	rootdir.mtime = time(NULL);
	strcpy(rootdir.user, g_curuser);
	strcpy(rootdir.group, g_curgroup);
	rootdir.count = 1;
	rootdir.direct_block[0] = block_addr;
	for (int i=1; i<10; i++)
	{
		rootdir.direct_block[i] = -1;
	}
	rootdir.filesize = BLOCK_SIZE;
	rootdir.indirect_block1 = -1;
	rootdir.access = CATALOG | CATALOG_PERMISS;

	/* 写回磁盘块 */
	disk_write(inode_addr, &rootdir, sizeof(inode));
	

	/* 创建目录及配置文件 */
	fs_mkdir(g_rootdir_addr, "home");
	fs_mkdir(g_rootdir_addr, "root");
	fs_mkdir(g_rootdir_addr, "etc");

	fs_cd(g_curdir_addr, "etc");

	char buf[100] = {0};

	/* 创建几个系统文件, 暂未使用 */
	sprintf(buf, "root:x:%d:%d\n", 0, 0);
	fs_create(g_curdir_addr, "passwd", buf);

	sprintf(buf, "root:root\n");
	fs_create(g_curdir_addr, "shadow", buf);
	fs_chmod(g_curdir_addr, "660", "shadow");

	sprintf(buf, "root::0:root\n");
	fs_create(g_curdir_addr, "group", buf);

	fs_cd(g_curdir_addr, "..");	/* 回到根目录 */
}

void fs_load()
{
	/* 读取超级块 */
	disk_read(gc_superblock_addr, &g_superblock, sizeof(superblock));

	/* 读取索引节点位图 */
	disk_read(gc_inode_bitmap_addr, g_inode_bitmap, sizeof(g_inode_bitmap));

	/* 读取数据块位图 */
	disk_read(gc_block_bitmap_addr, g_block_bitmap, sizeof(g_block_bitmap));
}

void fs_diskinfo()
{
	printf("superblock size:     %uB\n", g_superblock.superblock_size);
	printf("block size:          %uB\n", BLOCK_SIZE);
	printf("inode size:          %uB\n", g_superblock.inode_size);
	printf("block num:           %u\n", BLOCK_NUM);
	printf("inode num:           %u\n", INODE_NUM);
	printf("free block num:      %u\n", g_superblock.free_block_num);
	printf("free inode num:      %u\n", g_superblock.free_inode_num);
	printf("blocknum per group:  %u\n", g_superblock.blocknum_per_group);
	printf("superblock addr:     %u\n", gc_superblock_addr);
	printf("block bitmap addr:   %u\n", gc_block_bitmap_addr);
	printf("inode bitmap addr:   %u\n", gc_inode_bitmap_addr);
	printf("inode addr:          %u\n", gc_inode_addr);
	printf("block addr:          %u\n", gc_block_addr);
	printf("free addr:           %u\n", g_superblock.free_addr);

	double leave = ((double)g_superblock.free_block_num/BLOCK_NUM)*100;
	double leave_size = (double)(g_superblock.free_block_num * BLOCK_SIZE)/GB;
	double use_size = (double)((g_superblock.block_num-g_superblock.free_block_num) * BLOCK_SIZE)/GB;
	printf("\n磁盘已用(%-5.1lf%%):    %.2lf GB\n", 100-leave, use_size);
	printf("磁盘可用(%-5.1lf%%):    %.2lf GB\n", leave, leave_size);
	printf("磁盘总量:            %.2lf GB\n", (double)g_superblock.disk_size/GB);
}

/* extFS shell */
void fs_shell()
{
	char inputstr[100];
	char cmd[30], p1[30], p2[30];

	while (1)
    {
		printf("%s@%s:%s$ ", g_curuser, extFS, g_curdir);	

		memset(cmd, 0, 30);
		memset(p1, 0, 30);
		memset(p2, 0, 30);

		fgets(inputstr, sizeof inputstr, stdin);
		sscanf(inputstr, "%s%s%s", cmd, p1, p2);
	
		if      (cmdis("ls"))			fs_ls(g_curdir_addr);
		else if (cmdis("cd"))			fs_cd(g_curdir_addr, p1);
		else if (cmdis("mkdir"))		fs_mkdir(g_curdir_addr, p1);
		else if (cmdis("rmdir"))		fs_rmdir(g_curdir_addr, p1);
		else if (cmdis("diskinfo")) 	fs_diskinfo();
		else if (cmdis("touch"))		fs_touch(g_curdir_addr, p1);
		else if (cmdis("write"))		fs_write(g_curdir_addr, p1);
		else if (cmdis("cat"))			fs_cat(g_curdir_addr, p1);
		else if (cmdis("rm"))			fs_rm(g_curdir_addr, p1);
		else if (cmdis("cls"))			system("clear");
		else if (cmdis("pwd"))			printf("%s\n", g_curdir);
		else if (cmdis("bigfile"))		bigfile();
		else if (cmdis("chmod"))		fs_chmod(g_curdir_addr, p1, p2);
		else if (cmdis("format"))		fs_format();
		else if (cmdis("exit"))			fs_exit();
		else							print("are you ok");
	}
}

/* 分配block，返回block地址 */
void block_alloc(u_int32_t *blockaddr)
{
	int top;	/* 栈顶指针 */

	if (g_superblock.free_block_num == 0)
	{
		printf("没有空闲块可以分配\n");
		*blockaddr = -1;
		return;
	}
	else
	{
		top = (g_superblock.free_block_num-1) % g_superblock.blocknum_per_group;
	}
	
	if(top == 0)	/* 如果在空闲盘块栈栈底 */
	{
		*blockaddr = g_superblock.free_addr;    /* 将当前空闲盘块栈所在盘块地址返回 */

		g_superblock.free_addr = g_superblock.free[0];    /* 将空闲盘块栈地址指向下一个盘块 */
		
		/* 读取新的空闲盘块栈 */
		disk_read(g_superblock.free_addr, g_superblock.free, sizeof(g_superblock.free));
	}
	else	/* 如果不在栈底，则将栈顶指向的盘块地址返回，top--. */
	{
		*blockaddr = g_superblock.free[top];
		g_superblock.free[top] = -1;
		top--;
	}

	/* 空闲块数-1 */
	g_superblock.free_block_num--;

	/* 更新超级块 */
	disk_write(gc_superblock_addr, &g_superblock, sizeof(superblock));

	/* 更新block位图 */
	int block_in_map = (*blockaddr-gc_block_addr)/BLOCK_SIZE;

	g_block_bitmap[block_in_map] = 1;

	disk_write(gc_block_bitmap_addr + block_in_map, &g_block_bitmap[block_in_map], sizeof(char));
}

void block_free(u_int32_t block_addr)
{
	if ((block_addr-gc_block_addr) % BLOCK_SIZE != 0 )
	{
		print("不是磁盘块起始地址");
		return;
	}

	u_int32_t block_in_map = (block_addr-gc_block_addr) / BLOCK_SIZE;
	if (g_block_bitmap[block_in_map] == 0)
	{
		print("无法释放空闲磁盘块");
		return;
	}	

	int top;	/* 栈顶指针 */
	top = (g_superblock.free_block_num-1) % g_superblock.blocknum_per_group;
					
	/* 清空block内容 */
	char tmp[BLOCK_SIZE] = {0};
	disk_write(block_addr, tmp, sizeof(tmp));

	if (top == g_superblock.blocknum_per_group-1)
	{
		/* 该空闲块作为新的空闲块堆栈 */
		g_superblock.free[0] = g_superblock.free_addr;	/* 新的空闲块堆栈第一个地址指向旧的空闲块堆栈指针 */
		for (int i=1; i<g_superblock.blocknum_per_group; i++)
		{
			g_superblock.free[i] = -1;	/* 清空栈元素的其它地址 */
		}
		disk_write(block_addr, g_superblock.free, sizeof(g_superblock.free));

		g_superblock.free_addr = block_addr;
	}
	else
	{
		top++;
		g_superblock.free[top] = block_addr;
	}

	/* 更新超级块 */
	g_superblock.free_block_num++;	/* 空闲块数+1 */
	disk_write(gc_superblock_addr, &g_superblock, sizeof(superblock));

	/* 更新block位图 */
	g_block_bitmap[block_in_map] = 0;
	disk_write(block_in_map + gc_block_bitmap_addr, &g_block_bitmap[block_in_map], sizeof(int));

	return;
}

/* 分配inode，返回inode地址 */
void inode_alloc(u_int32_t *inodeaddr)
{
	if (g_superblock.free_inode_num == 0)
	{
		print("没有空闲inode可以分配");
		*inodeaddr = -1;
	}
	else
	{
		/* 顺序查找空闲的inode */
		for(int i=0; i<INODE_NUM; i++)
		{
			if(g_inode_bitmap[i] == 0)
			{
				/* 更新超级块 */
				g_superblock.free_inode_num--;

				disk_write(gc_superblock_addr, &g_superblock, sizeof(superblock));

				/* 更新inode位图 */
				g_inode_bitmap[i] = 1;

				disk_write(gc_inode_bitmap_addr + i, &g_inode_bitmap[i], sizeof(char));

				*inodeaddr = gc_inode_addr + i * g_superblock.inode_size;
				return;
			}
		}
	}
}

void inode_free(int inode_addr)
{
	if ((inode_addr-gc_inode_addr) % g_superblock.inode_size != 0)
	{
		print("不是i节点起始地址");
		return;
	}

	u_int16_t inode_in_map = (inode_addr-gc_inode_addr) / g_superblock.inode_size;

	if (g_inode_bitmap[inode_in_map] == 0)
	{
		print("不能回收未使用的inode");
		return;
	}	
	
	/* 清空inode内容 */
	inode tmp = {0};
	disk_write(inode_addr, &tmp, sizeof(tmp));

	/* 更新超级块 */
	g_superblock.free_inode_num++;
	disk_write(gc_superblock_addr, &g_superblock, sizeof(superblock));

	/* 更新inode位图 */
	g_inode_bitmap[inode_in_map] = 0;
	disk_write(gc_inode_addr + inode_in_map, &g_inode_bitmap[inode_in_map], sizeof(char));
}

/* 创建目录 */
void fs_mkdir(int curdir_addr, char *filename)
{
	if (strlen(filename) == 0)
	{
		printf("extFS: mkdir: 参数缺失\n");
		return;
	}

	if (strlen(filename) >= FILENAME_MAX2)
	{
		print("文件名长度超过限制");
		return;
	}

	/* 取出当前目录的inode */
	inode curdir;
	disk_read(curdir_addr, &curdir, sizeof(inode));
	
	int cnt = curdir.count + 1;	/* 目录项数 */
	
	catalog catalogs[CATALOGNUM_PER_BLOCK];

	int block_index = -1, catalog_index = -1;
	int i = 0;

	while (i < 10) /* 先查找前10个直接块中的160个文件 */
	{
		if (curdir.direct_block[i] == -1)
		{
			i++;
			continue;
		}

		/* 取出这个直接块，要加入的目录条目的位置 */
		disk_read(curdir.direct_block[i], catalogs, sizeof(catalogs));

		/* 遍历磁盘块中的所有文件项 */
		for(int j=0; j<CATALOGNUM_PER_BLOCK; j++)
		{
			if (strcmp(catalogs[j].filename, filename) == 0)
			{
				print("相同名称的文件已存在");
				return;
			}
			else if (strcmp(catalogs[j].filename, "") == 0)
			{
				/* 找到空闲位置  */
				if (block_index == -1)
				{
					block_index = i;
					catalog_index = j;
				}
			}
		}
		i++;
	}
	/* 间接块中查找未写 */

	if (block_index != -1)
	{
		disk_read(curdir.direct_block[block_index], catalogs, sizeof(catalogs));

		strcpy(catalogs[catalog_index].filename, filename);

		u_int32_t newinode_addr;
		inode_alloc(&newinode_addr);
		u_int32_t newblock_addr;
		block_alloc(&newblock_addr);

		if (newinode_addr == -1 || newblock_addr == -1)
		{
			print("创建目录失败");
			return;
		}

		catalogs[catalog_index].inode_addr = newinode_addr;

		inode newinode;
		newinode.id = (newinode_addr-gc_inode_addr)/g_superblock.inode_size;
		newinode.atime = time(NULL);
		newinode.ctime = time(NULL);
		newinode.mtime = time(NULL);
		strcpy(newinode.user, g_curuser);
		strcpy(newinode.group, g_curgroup);
		newinode.count = 2;    /* . .. */

		/* 设置 . 和 .. */
		catalog dirlist2[CATALOGNUM_PER_BLOCK] = {0};
		strcpy(dirlist2[0].filename, ".");
		strcpy(dirlist2[1].filename, "..");
		dirlist2[0].inode_addr = newinode_addr;
		dirlist2[1].inode_addr = curdir_addr;

		/* 写入到当前目录的磁盘块 */
		disk_write(newblock_addr, dirlist2, sizeof(dirlist2));

		newinode.direct_block[0] = newblock_addr;
		for(int k=1; k<10; k++)
		{
			newinode.direct_block[k] = -1;
		}

		newinode.filesize = BLOCK_SIZE;
		newinode.indirect_block1 = -1;
		newinode.access = CATALOG | CATALOG_PERMISS;

		/* 写入磁盘 */
		disk_write(newinode_addr, &newinode, sizeof(inode));

		/* 将当前目录的磁盘块写回 */
		disk_write(curdir.direct_block[block_index], catalogs, sizeof(catalogs));

		/* 写回inode */
		curdir.count++;
		disk_write(curdir_addr, &curdir, sizeof(inode));
		
		return;
	}
	else
	{
		print("没找到空闲目录项, 目录创建失败");
		return;
	}
}

/* 删除目录 */
void fs_rmdir(int curdir_addr, char *filename)
{
	if (strlen(filename) == 0)
	{
		printf("extFS: rmdir: 参数缺失\n");
		return;
	}

	if (strlen(filename) >= FILENAME_MAX2)
	{
		print("文件名长度超过限制");
		return;
	}

	if (strcmp(filename, ".")==0 || strcmp(filename, "..")==0)
	{
		printf("extFS: rmdir: %s: 不能更改\n", filename);
		return;
	}

	inode curdir_inode;
	disk_read(curdir_addr, &curdir_inode, sizeof(inode));

	int i = 0;
	while (i<10)
	{
		catalog catalogs[CATALOGNUM_PER_BLOCK] = {0};

		if (curdir_inode.direct_block[i] == -1)
		{
			i++;
			continue;
		}

		disk_read(curdir_inode.direct_block[i], &catalogs, sizeof(catalogs));

		for (int j=0; j<CATALOGNUM_PER_BLOCK; j++)
		{
			inode tmp;
			disk_read(catalogs[j].inode_addr, &tmp, sizeof(inode));

			if (strcmp(catalogs[j].filename, filename) == 0)
			{
				if (((tmp.access>>9)&1) == 1)	/* 是目录则处理 */
				{
					int bit;
					rightbit(tmp, &bit);

					if (((tmp.access>>bit>>0)&1) == 0 || ((tmp.access>>bit>>1)&1) == 0 || ((tmp.access>>bit>>2)&1) == 0)
					{
						print("没有权限");
						return;
					}

					fs_rm_rf(catalogs[j].inode_addr);

					/* 删除该目录条目，写回磁盘 */
					strcpy(catalogs[j].filename, "");
					catalogs[j].inode_addr = -1;
					disk_write(curdir_inode.direct_block[i], &catalogs, sizeof(catalogs));
					curdir_inode.count--;
					disk_write(curdir_addr, &curdir_inode, sizeof(inode));
					
				}
				else
				{
					printf("extFS: rmdir: %s: 是一个文件\n", filename);
				}

				return;
			}
		}
		i++;
	}
	
	printf("extFS: rmdir: %s: 没有那个文件或目录\n", filename);
}

/* 删除文件 */
void fs_rm(int curdir_addr, char *filename)
{
	if (strlen(filename) == 0)
	{
		printf("extFS: rm: 参数缺失\n");
		return;
	}

	if (strlen(filename) >= FILENAME_MAX2)
	{
		print("文件名长度超过限制");
		return;
	}

	inode curdir_inode;
	disk_read(curdir_addr, &curdir_inode, sizeof(inode));

	int block_index, catalog_index, ret;
	find_file_in_curdir(curdir_inode, filename, &block_index, &catalog_index, &ret);

	if (ret == 0)
	{
		/* 取得文件的inode */
		inode file_inode;

		catalog catalogs[CATALOGNUM_PER_BLOCK];

		disk_read(curdir_inode.direct_block[block_index], &catalogs, sizeof(catalogs));

		disk_read(catalogs[catalog_index].inode_addr, &file_inode, sizeof(inode));

		int bit;
		rightbit(file_inode, &bit);

		if (((file_inode.access>>bit>>0)&1) == 0 || ((file_inode.access>>bit>>1)&1) == 0 || ((file_inode.access>>bit>>2)&1) == 0)
		{
			print("没有权限");
			return;
		}

		/* 将文件内容从磁盘读出  */
		int buflen = file_inode.filesize;
		u_int32_t fp = 0;    /* 文件指针 */

		if (((file_inode.access>>9)&1) == 0)	/* 是普通文件 */
		{
			/* 先释放10个直接块 */
			for (int i=0; i<10; i++)
			{ 
				if(file_inode.direct_block[i] != -1)
				{
					block_free(file_inode.direct_block[i]);
				}
			}

			/* 释放一级索引块 */
			if (file_inode.indirect_block1 != -1)
			{
				for (int i=0; i<BLOCK_SIZE/sizeof(u_int32_t); i++)
				{
					u_int32_t block1_addr;

					disk_read(file_inode.indirect_block1+i*sizeof(u_int32_t), &block1_addr, sizeof(u_int32_t));

					if ((int)block1_addr < 0)
					{
						continue;
					}

					block_free(block1_addr);
				}

				block_free(file_inode.indirect_block1);
			}

			/* 释放二级索引块 */
			if (file_inode.indirect_block2 != -1)
			{
				for (int i=0; i<BLOCK_SIZE/sizeof(u_int32_t); i++)
				{
					u_int32_t block2_addr;

					if ((int)block2_addr < 0)
					{
						continue;
					}

					disk_read(file_inode.indirect_block2+i*sizeof(u_int32_t), &block2_addr, sizeof(u_int32_t));

					for (int j=0; j<BLOCK_SIZE/sizeof(u_int32_t); j++)
					{
						u_int32_t block1_addr;

						disk_read(block2_addr+j*sizeof(u_int32_t), &block1_addr, sizeof(u_int32_t));

						if ((int)block1_addr < 0)
						{
							continue;
						}

						block_free(block1_addr);
					}

					block_free(block2_addr);
				}

				block_free(file_inode.indirect_block2);
			}

			/* 释放三级索引块 */
			if (file_inode.indirect_block3 != -1)
			{
				for (int i=0; i<BLOCK_SIZE/sizeof(u_int32_t); i++)
				{
					u_int32_t block3_addr;

					disk_read(file_inode.indirect_block3+i*sizeof(u_int32_t), &block3_addr, sizeof(u_int32_t));

					if ((int)block3_addr < 0)		/* -1 在 u_int32_t 中是 4294967295, 需要强制转换成int再做判断 */
					{
						continue;
					}

					for (int j=0; j<BLOCK_SIZE/sizeof(u_int32_t); j++)
					{
						u_int32_t block2_addr;

						disk_read(block3_addr+j*sizeof(u_int32_t), &block2_addr, sizeof(u_int32_t));

						if ((int)block2_addr < 0)
						{
							// block_free(block2_addr);
							continue;
						}

						for (int k=0; k<BLOCK_SIZE/sizeof(u_int32_t); k++)
						{
							u_int32_t block1_addr;

							disk_read(block2_addr+k*sizeof(u_int32_t), &block1_addr, sizeof(u_int32_t));

							if ((int)block1_addr < 0)
							{
								continue;
							}

							block_free(block1_addr);
						}

						block_free(block2_addr);
					}

					block_free(block3_addr);
				}

				block_free(file_inode.indirect_block3);
			}
			/* block回收完成 */

			inode_free(catalogs[catalog_index].inode_addr);

			/* 更新当前目录 */
			strcpy(catalogs[catalog_index].filename, "");
			catalogs[catalog_index].inode_addr = -1;
			disk_write(curdir_inode.direct_block[block_index], &catalogs, sizeof(catalogs));
			curdir_inode.count--;
			disk_write(curdir_addr, &curdir_inode, sizeof(inode));
		}
		else
		{
			printf("extFS: rm: %s: 是一个目录\n", filename);
		}
	}
	else
	{
		printf("extFS: rm: %s: 没有那个文件\n", filename);
	}
}

/* 删除该文件节点下所有文件或目录 */
void fs_rm_rf(int inode_addr)
{
	inode curdir_inode;
	disk_read(inode_addr, &curdir_inode, sizeof(inode));

	/* 取出目录项数 */
	int cnt = curdir_inode.count;
	if (cnt <= 2)
	{
		block_free(curdir_inode.direct_block[0]);
		inode_free(inode_addr);
		return ;
	}

	int i = 0;
	while (i<10)
	{
		catalog catalogs[CATALOGNUM_PER_BLOCK] = {0};

		if (curdir_inode.direct_block[i] == -1)
		{
			i++;
			continue;
		}
		
		disk_read(curdir_inode.direct_block[i], &catalogs, sizeof(catalogs));

		int f = 0;
		for (int j=0; j<CATALOGNUM_PER_BLOCK; j++)
		{
			/* inode tmp; */
			if (!(strcmp(catalogs[j].filename, ".")==0 || !strcmp(catalogs[j].filename, "..")==0 || !strcmp(catalogs[j].filename, "")==0))
			{
				f = 1;
				fs_rm_rf(catalogs[j].inode_addr);	/* 递归删除 */
			}

			i++;
		}

		/* 该磁盘块已空，回收 */
		if (f)
		{
			block_free(curdir_inode.direct_block[i]);
		}	
	}
	/* 该inode已空，回收 */
	inode_free(inode_addr);
}

/* 切换目录 */
void fs_cd(int curdir_addr, char *filename)
{
	if (strlen(filename) == 0)
	{
		g_curdir_addr = g_rootdir_addr;
		strcpy(g_curdir, "/");
		return;
	}

	if (strcmp(filename, ".") == 0) /* 如果是当前目录直接返回 */
	{
		return;
	}
	else
	{
		inode curdir_inode;
		disk_read(curdir_addr, &curdir_inode, sizeof(inode));

		/* 依次取出inode对应的磁盘块，查找有没有名字为name的目录项 */
		int i = 0;

		int bit;
		rightbit(curdir_inode, &bit);

		while (i < 10)
		{
			catalog catalogs[CATALOGNUM_PER_BLOCK] = {0};
			if (curdir_inode.direct_block[i] == -1)
			{
				i++;
				continue;
			}

			disk_read(curdir_inode.direct_block[i], &catalogs, sizeof(catalogs));

			for(int j=0; j<CATALOGNUM_PER_BLOCK; j++)
			{
				if (strcmp(catalogs[j].filename, filename) == 0)
				{
					inode tmp;
					disk_read(catalogs[j].inode_addr, &tmp, sizeof(inode));

					if (((tmp.access>>9)&1) == 1)	/* 判断是否是目录 */
					{
						/* 检查权限 */
						if (((tmp.access>>bit>>0)&1) == 0)
						{
							printf("没有权限\n");
							return;
						}

						/* 切换目录 */
						g_curdir_addr = catalogs[j].inode_addr;

						if (strcmp(catalogs[j].filename, "..") == 0)
						{
							char *ret = strrchr(g_curdir, '/');
							*ret = '\0';

							if (strlen(g_curdir) == 0)
							{
								g_curdir[0]='/';
								g_curdir[1]='\0';
							}
						}
						else
						{
							if (g_curdir[strlen(g_curdir)-1] != '/')
							{
								strcat(g_curdir, "/");
							}
							
							strcat(g_curdir, catalogs[j].filename);
						}
						return;
					}
					else
					{
						printf("extFS: cd: %s: 不是目录\n", filename);
					}
				}
			}
			i++;
		}

		printf("extFS: cd: %s: 没有那个文件或目录\n", filename);
	}
}

/* 修改访问权限 */
void fs_chmod(int curdir_addr, char *access, char *filename)
{
	if (strlen(filename) == 0)
	{
		printf("extFS: chmod: 参数缺失\n");
		return;
	}

	if (strlen(access) != 3)
	{
		printf("extFS: chmod: %s 参数错误\n", access);
		return;
	}

	for (int i=0; i<3; i++)
	{
		if (access[i] != '0' && access[i] != '7' && access[i] != '6' && access[i] != '4' && access[i] != '5' && access[i] != '1')
		{
			printf("extFS: chmod: %s 参数错误\n", access);
			return;
		}
	}

	if (strlen(filename) >= FILENAME_MAX2)
	{
		print("文件名长度超过限制");
		return;
	}

	if (strcmp(filename, ".")==0 || strcmp(filename, "..")==0)
	{
		printf("extFS: chmod: %s: 不能更改\n", filename);
		return;
	}

	inode curdir_inode, file_inode;
	disk_read(curdir_addr, &curdir_inode, sizeof(inode));

	catalog catalogs[CATALOGNUM_PER_BLOCK] = {0};

	int i = 0;
	int j = 0;
	while (i < 10)
	{
		if (curdir_inode.direct_block[i] == -1)
		{
			i++;
			continue;
		}

		disk_read(curdir_inode.direct_block[i], &catalogs, sizeof(catalogs));

		for (j=0; j<CATALOGNUM_PER_BLOCK; j++)
		{
			if (strcmp(catalogs[j].filename, filename) == 0)
			{
				disk_read(catalogs[j].inode_addr, &file_inode, sizeof(inode));

				goto outofwhile;
			}
		}
		i++;
	}

outofwhile:
	if (i >= 10)
	{
		printf("extFS: cd: %s: 没有那个文件或目录\n", filename);
		return ;
	}

	/* 检查权限 */
	if (strcmp(g_curuser, file_inode.user)!=0 && strcmp(g_curuser, "root") != 0)
	{
		print("没有权限");
		return ;
	}

	/* 更改访问权限 */
	int a = strtol(access, NULL, 8); 
	file_inode.access = (file_inode.access>>9<<9) | a;

	/* 写入磁盘 */
	disk_write(catalogs[j].inode_addr, &file_inode, sizeof(inode));
}

/* 创建一个新文件 */
void fs_touch(int curdir_addr, char *filename)
{
	if (strlen(filename) == 0)
	{
		printf("extFS: touch: 参数缺失\n");
		return;
	}

	if (strlen(filename) >= FILENAME_MAX2)
	{
		print("文件名长度超过限制");
		return;
	}

	catalog catalogs[CATALOGNUM_PER_BLOCK];

	inode curdir_inode, file_inode;
	disk_read(curdir_addr, &curdir_inode, sizeof(inode));

	int bit;
	rightbit(curdir_inode, &bit);
	
	int i = 0;
	int file_inode_addr = -1;

	while (i<10)
	{
		if (curdir_inode.direct_block[i] == -1)
		{
			i++;
			continue;
		}

		disk_read(curdir_inode.direct_block[i], catalogs, sizeof(catalogs));

		for (int j=0; j<CATALOGNUM_PER_BLOCK; j++)
		{
			if (strcmp(catalogs[j].filename, filename) == 0)
			{
				disk_read(catalogs[j].inode_addr, &file_inode, sizeof(inode));

				if (((file_inode.access>>9)&1) == 0)
				{
					printf("文件已存在\n");
					return ;
				}
			}
		}
		i++;
	}

	/* 文件不存在，创建一个空文件 */
	if (((curdir_inode.access>>bit>>1)&1) == 1)
	{
		char buf[1] = "\0";
		fs_create(curdir_addr, filename, buf);
	}
	else
	{
		print("没有权限");
		return ;
	}
}

/* 将buf内容写入文件(覆盖) */
void fs_write(int curdir_addr, char *filename)
{
	if (strlen(filename) == 0)
	{
		printf("extFS: write: 参数缺失\n");
		return;
	}

	if (strlen(filename) >= FILENAME_MAX2)
	{
		print("文件名长度超过限制");
		return;
	}

	inode curdir_inode;
	disk_read(curdir_addr, &curdir_inode, sizeof(inode));

	int block_index, catalog_index, ret;
	find_file_in_curdir(curdir_inode, filename, &block_index, &catalog_index, &ret);

	if (ret == 0)
	{
		/* 取得文件的inode */
		inode file_inode;

		catalog catalogs[CATALOGNUM_PER_BLOCK];

		disk_read(curdir_inode.direct_block[block_index], &catalogs, sizeof(catalogs));

		disk_read(catalogs[catalog_index].inode_addr, &file_inode, sizeof(inode));

		int bit;
		rightbit(file_inode, &bit);

		printd(file_inode.access);
		if (((file_inode.access>>bit>>1)&1) == 0)
		{
			print("没有权限");
			return;
		}

		if ((file_inode.access>>9)&1 == 1)
		{
			printf("extFS: write: %s: 是一个目录\n", filename);
			return;
		}

		char inputstr[100000];
		print("请输入文件内容:");
		fgets(inputstr, sizeof inputstr, stdin);
		sscanf(inputstr, "%s", inputstr);

		int buflen = strlen(inputstr);
		int fp = 0;    /* 文件指针 */

		/* 先写10个直接块 */
		for (int i=0; i<10; i++)
		{
			if (buflen > 0)
			{
				u_int32_t newblock_addr;

				if (file_inode.direct_block[i] == -1)
				{
					block_alloc(&newblock_addr);
					if (newblock_addr == -1)
					{
						print("block分配失败");
						return ;
					}

					file_inode.direct_block[i] = newblock_addr;
				}
				else
				{
					newblock_addr = file_inode.direct_block[i];
				}
				
				if (buflen > BLOCK_SIZE)
				{
					disk_write(newblock_addr, inputstr+fp, BLOCK_SIZE);
				}
				else
				{
					disk_write(newblock_addr, inputstr+i, buflen);
				}

				buflen -= BLOCK_SIZE;
				fp += BLOCK_SIZE;
			}
		}

		/* 更新该文件大小 */
		file_inode.filesize = strlen(inputstr);
		file_inode.mtime = time(NULL);
		disk_write(catalogs[catalog_index].inode_addr, &file_inode, sizeof(inode));
	}
	else
	{
		printf("extFS: write: %s: 没有那个文件或目录\n", filename);
	}
}

/* 打印文件内容 */
void fs_cat(int curdir_addr, char *filename)
{
	if (strlen(filename) == 0)
	{
		printf("extFS: cat: 参数缺失\n");
		return;
	}

	if (strlen(filename) >= FILENAME_MAX2)
	{
		print("文件名长度超过限制");
		return;
	}

	inode curdir_inode;
	disk_read(curdir_addr, &curdir_inode, sizeof(inode));
	
	int block_index, catalog_index, ret;
	find_file_in_curdir(curdir_inode, filename, &block_index, &catalog_index, &ret);

	if (ret == 0)
	{
		/* 取到file inode */
		inode file_inode;

		catalog catalogs[CATALOGNUM_PER_BLOCK];
		disk_read(curdir_inode.direct_block[block_index], catalogs, sizeof(catalogs));

		disk_read(catalogs[catalog_index].inode_addr, &file_inode, sizeof(inode));

		if (((file_inode.access>>9)&1) == 1)
		{
			printf("extFS: cat: %s: 是一个目录\n", filename);
			return;
		}

		/* 读文件内容到缓冲区 */
		char *buf = (char*)malloc(file_inode.filesize);

		/* 将文件内容从磁盘读出  */
		int buflen = file_inode.filesize;
		u_int32_t fp = 0;    /* 文件指针 */

		/* 先读10个直接块 */
		for (int i=0; i<10; i++)
		{
			if (buflen > 0)
			{
				if (buflen >= BLOCK_SIZE)
				{
					disk_read(file_inode.direct_block[i], buf+fp, BLOCK_SIZE);
				}
				else
				{
					disk_read(file_inode.direct_block[i], buf+fp, buflen);
				}

				buflen -= BLOCK_SIZE;
				fp += BLOCK_SIZE;
			}
			else
			{
				goto du_wan_le;    /* 读完了 */
			}
		}
		
		/* 1级索引 */
		if (buflen > 0)
		{
			for (int i=0; i<BLOCK_SIZE/sizeof(u_int32_t); i++)
			{
				if (buflen > 0)
				{
					u_int32_t block1_addr;

					disk_read(file_inode.indirect_block1+i*sizeof(u_int32_t), &block1_addr, sizeof(u_int32_t));

					if (block1_addr < 0)
					{
						print("读取文件出错, 文件内容损坏");
						return;
					}

					if (buflen > BLOCK_SIZE)
					{
						disk_read(block1_addr, buf+fp, BLOCK_SIZE);
					}
					else
					{
						disk_read(block1_addr, buf+fp, buflen);
					}

					buflen -= BLOCK_SIZE;
					fp += BLOCK_SIZE;
				}
				else
				{
					goto du_wan_le;    /* 读完了 */
				}
			}
		}

		/* 2级索引 */
		if (buflen > 0)
		{
			for (int i=0; i<BLOCK_SIZE/sizeof(u_int32_t); i++)
			{
				if (buflen > 0)
				{
					u_int32_t block2_addr;

					disk_read(file_inode.indirect_block2+i*sizeof(u_int32_t), &block2_addr, sizeof(u_int32_t));

					for (int j=0; j<BLOCK_SIZE/sizeof(u_int32_t); j++)
					{
						if (buflen > 0)
						{
							u_int32_t block1_addr;

							disk_read(block2_addr+j*sizeof(u_int32_t), &block1_addr, sizeof(u_int32_t));

							if (block1_addr < 0)
							{
								print("读取文件出错, 文件内容损坏");
								return;
							}

							if (buflen > BLOCK_SIZE)
							{
								disk_read(block1_addr, buf+fp, BLOCK_SIZE);
							}
							else
							{
								disk_read(block1_addr, buf+fp, buflen);
							}

							buflen -= BLOCK_SIZE;
							fp += BLOCK_SIZE;
						}
						else
						{
							goto du_wan_le;    /* 读完了 */
						}
					}
				}
				else
				{
					goto du_wan_le;    /* 读完了 */
				}
			}
		}

		/* 3级索引 */
		if (buflen > 0)
		{
			for (int i=0; i<BLOCK_SIZE/sizeof(u_int32_t); i++)
			{
				if (buflen > 0)
				{
					u_int32_t block3_addr;

					disk_read(file_inode.indirect_block3+i*sizeof(u_int32_t), &block3_addr, sizeof(u_int32_t));

					for (int j=0; j<BLOCK_SIZE/sizeof(u_int32_t); j++)
					{
						if (buflen > 0)
						{
							u_int32_t block2_addr;

							disk_read(block3_addr+j*sizeof(u_int32_t), &block2_addr, sizeof(u_int32_t));

							for (int k=0; k<BLOCK_SIZE/sizeof(u_int32_t); k++)
							{
								if (buflen > 0)
								{
									u_int32_t block1_addr;

									disk_read(block2_addr+k*sizeof(u_int32_t), &block1_addr, sizeof(u_int32_t));

									if (block1_addr < 0)
									{
										print("读取文件出错, 文件内容损坏");
										return;
									}

									if (buflen > BLOCK_SIZE)
									{
										disk_read(block1_addr, buf+fp, BLOCK_SIZE);
									}
									else
									{
										disk_read(block1_addr, buf+fp, buflen);
									}

									buflen -= BLOCK_SIZE;
									fp += BLOCK_SIZE;
								}
								else
								{
									goto du_wan_le;    /* 读完了 */
								}
							}
						}
						else
						{
							goto du_wan_le;    /* 读完了 */
						}
					}
				}
				else
				{
					goto du_wan_le;    /* 读完了 */
				}
			}
		}

	du_wan_le:
		fp = file_inode.filesize;
		buf[fp] = '\0';
		printf("%s\n", buf);

		if (fp >= GB)
		{
			printf("读出内容大小 %.2lf%s\n", (double)fp/GB, "GB");
		}
		else if (fp >= MB)
		{
			printf("读出内容大小 %.2lf%s\n", (double)fp/MB, "MB");
		}
		else if (fp >= KB)
		{
			printf("读出内容大小 %.2lf%s\n", (double)fp/KB, "KB");
		}
		else
		{
			printf("读出内容大小 %u%s\n", fp, "B");
		}

		free(buf);
	}
	else
	{
		printf("extFS: cat: %s: 没有那个文件或目录\n", filename);
	}
}

/* 打印当前目录下文件项 */
void fs_ls(int curdir_addr)
{
	inode curdir_inode;

	disk_read(curdir_addr, &curdir_inode, sizeof(inode));

	int cnt = curdir_inode.count;

	int bit;
	rightbit(curdir_inode, &bit);

	if (((curdir_inode.access>>bit>>2)&1) == 0)
	{
		print("没有权限");
		return ;
	}

	int i = 0;
	while (i<cnt && i<160)
	{	
		catalog catalogs[CATALOGNUM_PER_BLOCK] = {0};
		if (curdir_inode.direct_block[i/CATALOGNUM_PER_BLOCK] == -1)
		{
			i+=CATALOGNUM_PER_BLOCK;
			continue;
		}

		disk_read(curdir_inode.direct_block[i/CATALOGNUM_PER_BLOCK], &catalogs, sizeof(catalogs));

		int j;
		for (j=0; j<CATALOGNUM_PER_BLOCK && i<cnt; j++)
		{
			inode tmp;
			
			disk_read(catalogs[j].inode_addr, &tmp, sizeof(inode));

			if (strcmp(catalogs[j].filename, "") == 0)
			{
				continue;
			}

			if (((tmp.access>>9)&1) == 1)
			{
				printf("d");
			}
			else
			{
				printf("-");
			}

			struct tm *last = gmtime(&tmp.mtime);

			int t = 8;
			while (t>=0)
			{
				if (((tmp.access>>t)&1) == 1)
				{
					if (t%3 == 2)	printf("r");
					if (t%3 == 1)	printf("w");
					if (t%3 == 0)	printf("x");
				}
				else
				{
					printf("-");
				}

				t--;
			}

			printf("  %d  %s  %s", tmp.count, tmp.user, tmp.group);

			if (tmp.filesize >= GB)
			{
				printf("  %.2lf%s", (double)tmp.filesize/GB, "GB");
			}
			else if (tmp.filesize >= MB)
			{
				printf("  %.2lf%s", (double)tmp.filesize/MB, "MB");
			}
			else if (tmp.filesize >= KB)
			{
				printf("  %.2lf%s", (double)tmp.filesize/KB, "KB");
			}
			else
			{
				printf("  %d%s", tmp.filesize, "B");
			}
			
			printf("  %d/%d/%d %02d:%02d:%02d", last->tm_year + 1900, last->tm_mon+1, last->tm_mday, (8+last->tm_hour)%24, last->tm_min, last->tm_sec);
			printf("  %s\n", catalogs[j].filename);

			i++;
		}
	}
}

/* 创建一个新文件, 内容是buf */
void fs_create(int curdir_addr, char *filename, char *buf)
{
	if (strlen(filename) == 0)
	{
		printf("extFS: create: 参数缺失\n");
		return;
	}

	if (strlen(filename) >= FILENAME_MAX2)
	{
		print("文件名长度超过限制");
		return;
	}

	inode curdir_inode;
	disk_read(curdir_addr, &curdir_inode, sizeof(inode));
	
	int block_index, catalog_index, ret;
	find_file_in_curdir(curdir_inode, filename, &block_index, &catalog_index, &ret);

	if (ret == 1)
	{
		/* 申请inode */
		u_int32_t newinode_addr;
		inode_alloc(&newinode_addr);
		if (newinode_addr == -1)
		{
			print("inode分配失败");
			return;
		}

		/* 设置inode */
		inode new_inode;
		new_inode.id = (newinode_addr-gc_inode_addr)/g_superblock.inode_size;
		new_inode.atime = time(NULL);
		new_inode.ctime = time(NULL);
		new_inode.mtime = time(NULL);
		strcpy(new_inode.user, g_curuser);
		strcpy(new_inode.group, g_curgroup);
		new_inode.count = 1;

		/* 将文件内容写入磁盘  */
		int buflen = strlen(buf);
		int fp = 0;    /* 文件指针 */

		/* 先写入10个直接块 */
		for (int i=0; i<10; i++)
		{
			if (buflen > 0)
			{
				u_int32_t newblock_addr;
				block_alloc(&newblock_addr);
				if (newblock_addr == -1)
				{
					print("block分配失败");
					return;
				}

				new_inode.direct_block[i] = newblock_addr;

				if (buflen > BLOCK_SIZE)
				{
					disk_write(newblock_addr, buf+fp, BLOCK_SIZE);
				}
				else
				{
					disk_write(newblock_addr, buf+fp, buflen);
				}

				buflen -= BLOCK_SIZE;
				fp += BLOCK_SIZE;
			}
			else
			{
				new_inode.direct_block[i] = -1;
			}
		}
		
		/* 1级索引 */
		if (buflen > 0)
		{
			u_int32_t indirect_block1_addr;
			block_alloc(&indirect_block1_addr);
			if (indirect_block1_addr == -1)
			{
				print("block分配失败");
				return;
			}
			
			new_inode.indirect_block1 = indirect_block1_addr;

			for (int i=0; i<BLOCK_SIZE/sizeof(u_int32_t); i++)
			{
				u_int32_t block1_addr;	/* 一级间接块地址 */

				if (buflen > 0)
				{
					block_alloc(&block1_addr);
					if (block1_addr == -1)
					{
						print("block分配失败");
						return;
					}
					
					if (buflen > BLOCK_SIZE)
					{
						disk_write(block1_addr, buf+fp, BLOCK_SIZE);
					}
					else
					{
						disk_write(block1_addr, buf+fp, buflen);
					}

					buflen -= BLOCK_SIZE;
					fp += BLOCK_SIZE;
				}
				else
				{
					block1_addr = -1;
					
				}

				disk_write(indirect_block1_addr+i*sizeof(u_int32_t), &block1_addr, sizeof(u_int32_t));
			}
		}
		else
		{
			new_inode.indirect_block1 = -1;
		}
		

		/* 2级索引 */
		if (buflen > 0)
		{
			u_int32_t indirect_block2_addr;
			block_alloc(&indirect_block2_addr);
			if (indirect_block2_addr == -1)
			{
				print("block分配失败");
				return;
			}
			
			new_inode.indirect_block2 = indirect_block2_addr;

			for (int i=0; i<BLOCK_SIZE/sizeof(u_int32_t); i++)
			{
				u_int32_t block2_addr;	/* 二级间接块地址 */

				if (buflen > 0)
				{
					block_alloc(&block2_addr);
					if (block2_addr == -1)
					{
						print("block分配失败");
						return;
					}

					for (int j=0; j<BLOCK_SIZE/sizeof(u_int32_t); j++)
					{
						u_int32_t block1_addr;	/* 一级间接块地址 */

						if (buflen > 0)
						{
							block_alloc(&block1_addr);
							if (block1_addr == -1)
							{
								print("block分配失败");
								return;
							}

							if (buflen > BLOCK_SIZE)
							{
								disk_write(block1_addr, buf+fp, BLOCK_SIZE);
							}
							else
							{
								disk_write(block1_addr, buf+fp, buflen);
							}

							buflen -= BLOCK_SIZE;
							fp += BLOCK_SIZE;
						}
						else
						{
							block1_addr = -1;
						}

						disk_write(block2_addr+j*sizeof(u_int32_t), &block1_addr, sizeof(u_int32_t));
					}
				}
				else
				{
					block2_addr = -1;		
				}

				disk_write(indirect_block2_addr+i*sizeof(u_int32_t), &block2_addr, sizeof(u_int32_t));
			}
		}
		else
		{
			new_inode.indirect_block2 = -1;
		}

		/* 3级索引 */
		if (buflen > 0)
		{
			u_int32_t indirect_block3_addr;
			block_alloc(&indirect_block3_addr);
			if (indirect_block3_addr == -1)
			{
				print("block分配失败");
				return;
			}
			
			new_inode.indirect_block3 = indirect_block3_addr;

			for (int i=0; i<BLOCK_SIZE/sizeof(u_int32_t); i++)
			{
				u_int32_t block3_addr;	/* 三级间接块地址 */

				if (buflen > 0)
				{
					block_alloc(&block3_addr);
					if (block3_addr == -1)
					{
						print("block分配失败");
						return;
					}

					for (int j=0; j<BLOCK_SIZE/sizeof(u_int32_t); j++)
					{
						u_int32_t block2_addr;	/* 二级间接块地址 */

						if (buflen > 0)
						{
							block_alloc(&block2_addr);
							if (block2_addr == -1)
							{
								print("block分配失败");
								return;
							}

							for (int k=0; k<BLOCK_SIZE/sizeof(u_int32_t); k++)
							{
								u_int32_t block1_addr;	/* 一级间接块地址 */

								if (buflen > 0)
								{
									block_alloc(&block1_addr);
									if (block1_addr == -1)
									{
										print("block分配失败");
										return;
									}

									if (buflen > BLOCK_SIZE)
									{
										disk_write(block1_addr, buf+fp, BLOCK_SIZE);
									}
									else
									{
										disk_write(block1_addr, buf+fp, buflen);
									}

									buflen -= BLOCK_SIZE;
									fp += BLOCK_SIZE;
								}
								else
								{
									block1_addr = -1;
								}

								disk_write(block2_addr+k*sizeof(u_int32_t), &block1_addr, sizeof(u_int32_t));
							}
						}
						else
						{
							block2_addr = -1;		
						}

						disk_write(block3_addr+j*sizeof(u_int32_t), &block2_addr, sizeof(u_int32_t));
					}
				}
				else
				{
					block3_addr = -1;		
				}

				disk_write(indirect_block3_addr+i*sizeof(u_int32_t), &block3_addr, sizeof(u_int32_t));
			}
		}
		else
		{
			new_inode.indirect_block3 = -1;
		}

		new_inode.filesize = strlen(buf);
		new_inode.access = NORMAL_FILE | NORMAL_FILE_PERMISS;

		/* 将inode写入磁盘 */
		disk_write(newinode_addr, &new_inode, sizeof(inode));

		/* 更新当前目录项 */
		catalog catalogs[CATALOGNUM_PER_BLOCK];
		disk_read(curdir_inode.direct_block[block_index], catalogs, sizeof(catalogs));

		strcpy(catalogs[catalog_index].filename, filename);
		catalogs[catalog_index].inode_addr = newinode_addr;
		
		disk_write(curdir_inode.direct_block[block_index], catalogs, sizeof(catalogs));

		/* 更新当前目录inode */
		curdir_inode.count++;
		disk_write(curdir_addr, &curdir_inode, sizeof(inode));
	}
}

void fs_exit()
{
	print("正在保存。。。");

	rename(extFS, BACKUP_FILE);

	fclose(g_ifp);
	fclose(g_ofp);

	exit(0);
}

/* 返回文件权限对应bit */
void rightbit(inode curdir_inode, int *bit)
{
	if (strcmp(g_curuser, curdir_inode.user) == 0)
	{
		*bit = 6;
	}
	else if (strcmp(g_curuser, curdir_inode.group) == 0)
	{
		*bit = 3;
	}
	else
	{
		*bit = 0;
	}
}

/* 查找当前目录下是否存在同名文件, 存在则返回文件索引, 如不存在返回可用的文件项索引 */
void find_file_in_curdir(inode curdir_inode, char *filename, int *block_index, int *catalog_index, int *ret)
{
	*block_index = -1;
	*catalog_index = -1;

	/* 首先查找10个直接块 */
	for (int i=0; i<10; i++)
	{
		if (curdir_inode.direct_block[i] == -1)
		{
			continue;
		}

		catalog catalogs[CATALOGNUM_PER_BLOCK];
		disk_read(curdir_inode.direct_block[i], catalogs, sizeof(catalogs));

		for(int j=0; j<CATALOGNUM_PER_BLOCK; j++)
		{
			if (strcmp(catalogs[j].filename, filename) == 0)
			{
				// print("相同名称的文件已存在");
				*block_index = i;
				*catalog_index = j;
				*ret = 0;	/* 表示存在同名文件 */
				return;
			}
			else if (strcmp(catalogs[j].filename, "") == 0)    /* 找到可用项 */
			{
				if (*block_index == -1)
				{
					*block_index = i;
					*catalog_index = j;
					*ret = 1;
				}
			}
		}
	}

	/* 查找1级索引 */
	if (curdir_inode.indirect_block1 != -1)
	{
		//未完成
	}

	/* 查找2级索引 */
	if (curdir_inode.indirect_block2 != -1)
	{

	}

	/* 查找3级索引 */
	if (curdir_inode.indirect_block3 != -1)
	{

	}
}

void bigfile()
{
	u_int32_t filesize = 500*MB;

	char *buf = (char*)malloc(filesize);

	memset(buf, 'b', filesize);
	buf[filesize-1] = '\0';

	print("开始创建一个500M的文件");
	fs_create(g_curdir_addr, "big", buf);

	free(buf);
}
